package main

import "fmt"

func main() {
	//切片slice：基于数组的封装  拥有变长功能。 底层是数组
	//切片定义
	var s1 []int //存放int类型的切片  长度不给 不固定的长度
	//数组：var s [3]int
	var s2 []string
	fmt.Println(s1, s2)
	fmt.Println(s1 == nil) //go中nil表示空

	//切片初始化
	s1 = []int{1, 2, 3, 4, 5, 6, 7}
	s2 = []string{"a", "b", "cc"}
	fmt.Println(s1, s2)
	fmt.Println(s1 == nil) //false nil表示没有分配内存空间

	//切片长度和容量
	fmt.Printf("len(s1) : %d  cap(s1) : %d\n", len(s1), cap(s1))
	fmt.Printf("len(s2) : %d  cap(s2) : %d\n", len(s2), cap(s2))

	//由数组得到切片
	a1 := [6]int{1, 3, 5, 6, 8, 9}
	s3 := a1[0:3] //数组[i:j]  数组切割操作： 左闭右开  取到的长度为j-i
	s4 := a1[:5]
	s5 := a1[5:]
	s6 := a1[:]
	fmt.Println(s3, s4, s5, s6)
	fmt.Printf("len(s4) : %d  cap(s4) : %d\n", len(s4), cap(s4)) //len(s4) : 5  cap(s4) : 6
	fmt.Printf("len(s5) : %d  cap(s5) : %d\n", len(s5), cap(s5)) //len(s5) : 1  cap(s5) : 1
	//切片容量指底层数组从（切片*的第一个元素）到（数组*的最后一个元素）的的长度，
	//长度指当前切片的长度。
	//s4  1 -> 9 : cap = 6
	//s5  9 -> 9 : cap = 1

	//切片再切片
	s7 := s4[2:4]
	fmt.Println(s7)
	fmt.Printf("len(s7) : %d  cap(s7) : %d\n", len(s7), cap(s7)) //len(s7) : 2  cap(s7) : 4

	//切片的本质 ： 是引用类型  指向底层数组地址
	//切片本身不保存值，只保存引用
	fmt.Println(s6) //[1 3 5 6 8 9]
	a1[1] = 1300    //s6 := a1[:]
	fmt.Println(s6) //[1 1300 5 6 8 9]
	fmt.Println(s3) //[1 1300 5]
	fmt.Println(s4) //[1 1300 5 6 8]

	fmt.Println("===================================================")

	//make函数构造切片
	ms1 := make([]int, 5, 10)                                        //make(数组类型, 长度, 容量(不定义默认为长度))
	fmt.Printf("len(ms1) : %d  cap(ms1) : %d\n", len(ms1), cap(ms1)) //len(ms1) : 5  cap(ms1) : 10
	//初始的长度是切片长度，容量是底层数组长度

	//切片和nil
	//未开辟内存空间的为nil  开辟了的不为nil  和切片长度没有必然关系
	var s8 []int
	s9 := []int{}
	ms2 := make([]int, 0, 10)
	fmt.Println(s8 == nil, s9 == nil, ms2 == nil) //true false false

	//切片的赋值
	s10 := []int{1, 2, 3, 4, 5}
	s11 := s10
	fmt.Println(s10, s11) //[1 2 3 4 5] [1 2 3 4 5]
	s11[0] = 888
	s10[4] = 666
	fmt.Println(s10, s11) //[888 2 3 4 666] [888 2 3 4 666]

	//切片的遍历
	for i, v := range s10 {
		fmt.Println(i, v)
	}
	fmt.Println()
	for i := 0; i < len(s10); i++ {
		fmt.Println(i, s10[i])
	}

	//append 为切片增加元素
	s12 := []string{"bj", "sh", "gz"}
	fmt.Printf("len(s12) : %d  cap(s12) : %d\n", len(s12), cap(s12)) //len(s12) : 3  cap(s12) : 3
	// s12[3] = "sz" 错误写法  因为底层数组容量不足
	s12 = append(s12, "sz") //调用append函数  必须使用原来的那个切片变量接收返回值
	fmt.Println(s12)
	fmt.Printf("len(s12) : %d  cap(s12) : %d\n", len(s12), cap(s12)) //len(s12) : 4  cap(s12) : 6
	//cap(s12) : 3 -> cap(s12) : 6   为s12底层数组分配了一块 新的 更大的 地址空间
	ss := []string{"hf", "wh", "zz"}
	s12 = append(s12, ss...)                                         //...表示拆开  一堆元素
	fmt.Printf("len(s12) : %d  cap(s12) : %d\n", len(s12), cap(s12)) //len(s12) : 7  cap(s12) : 12

	//切片深复制 copy
	var s13 = make([]string, len(s12))
	copy(s13, s12)
	fmt.Println(s12, s13) //[bj sh gz sz hf wh zz] [bj sh gz sz hf wh zz]
	s12[0] = "xxxxxx"
	fmt.Println(s12, s13) //[xxxxxx sh gz sz hf wh zz] [bj sh gz sz hf wh zz]	深复制  不是浅复制

	//切片删除元素 ： append + [i:] [:j]
	//切片没有删除元素功能  可以用append实现
	fmt.Printf("len(s12) : %d  cap(s12) : %d\n", len(s12), cap(s12)) //len(s12) : 7  cap(s12) : 12
	s12 = append(s12[:3], s12[4:]...)                                //删除index = 3元素
	fmt.Println(s12)
	fmt.Printf("len(s12) : %d  cap(s12) : %d\n", len(s12), cap(s12)) //len(s12) : 6  cap(s12) : 12
	//实际上这个操作修改了底层数组！  把index=3的元素用后面的元素覆盖掉了

	//切片修改底层数组的实例
	var ms3 = make([]int, 5, 10)
	fmt.Println(ms3)
	for i := 1; i <= 10; i++ {
		ms3 = append(ms3, i) //在原先0 0 0 0 0的基础上附加值
	}
	fmt.Println(ms3)      //[0 0 0 0 0 1 2 3 4 5 6 7 8 9 10]
	fmt.Println(cap(ms3)) //20

}
